# -*- coding: utf-8 -*-
import json
from functools import partial, wraps
from typing import Type

import marshmallow
from django.core.handlers.wsgi import WSGIRequest
from django.http import JsonResponse, HttpResponseNotAllowed
from marshmallow import ValidationError

from firstDjango.exceptions import FormException


def dump_form_data(func):
    """
    将post请求的body dump成form_data 塞进request中
    :param func:
    :return:
    """

    def wrapper(request, *args, **kw):
        try:
            form_data = json.loads(request.body.decode('utf-8'))
        except json.JSONDecodeError:
            raise FormException('表单数据异常')
        setattr(request, 'form_data', form_data)
        return func(request, *args, **kw)

    return wrapper


def _load_response(resp, response_schema: Type[marshmallow.Schema]):
    schema = response_schema()
    result = schema.dump(resp)
    errors = schema.validate(result)
    if errors:
        print(errors)
    return result


def _validate_data_class_type(*data_class):
    for clazz in data_class:
        if clazz:
            if not hasattr(clazz, 'Schema'):
                raise NotImplementedError("不支持的data_class类型: %s", clazz)


def _get_post_data(req: WSGIRequest):
    try:
        return json.loads(req.body.decode('utf-8'))
    except json.JSONDecodeError:
        raise FormException('表单数据异常')


def ajax(method: str, *, request_data_class=None, response_data_class=None):
    _validate_data_class_type(request_data_class, response_data_class)

    def _ajax(func):
        @wraps(func)
        def wrapper(request: WSGIRequest, *args, **kwargs):
            if request.method != method:
                return HttpResponseNotAllowed([method])
            if method == "GET":
                data = request.GET
            elif method == "POST":
                data = _get_post_data(request)
            else:
                return HttpResponseNotAllowed([method])
            if request_data_class:
                try:
                    data = request_data_class.Schema().load(data=data)
                except ValidationError as e:
                    return JsonResponse({"code": -200, "message": "请求参数不合法", "errors": e.messages})
                resp = func(request, data, *args, **kwargs)
            else:
                resp = func(request, *args, **kwargs)
            if response_data_class:
                return _load_response(resp, response_data_class.Schema)
            return resp or "ok"

        return wrapper

    return _ajax


get = partial(ajax, "GET")
post = partial(ajax, "POST")
